﻿using MvvmCross.Core.ViewModels;
using MvvmCross.Plugins.Messenger;
using Sidvall.UI.Messaging;
using System.Collections.Generic;
using System.Threading.Tasks;

namespace Sidvall.UI.ViewModels
{
    public abstract class NavigatingObjectBase : MvxNavigatingObject, System.IDisposable
    {
        #region Public Members

        // Protected
        #region ViewModelResources

        private System.Lazy<ViewModelResourceCollection> _ViewModelResources = new System.Lazy<ViewModelResourceCollection>();
        protected ViewModelResourceCollection ViewModelResources
        {
            get
            {
                return _ViewModelResources.Value;
            }
        }

        #endregion

        #region ChangePresentation

        protected void ChangePresentation(ViewModels.ViewModelActionType type)
        {
            ChangePresentation(type, null);
        }
        protected void ChangePresentation(ViewModels.ViewModelActionType type, string context)
        {
            PresentationHint hint;

            hint = new PresentationHint()
            {
                ActionType = type,
                Context = context,
            };
            ChangePresentation(hint);
        }

        #endregion
        #region OnCultureChanged

        protected virtual void OnCultureChanged(CultureMessage item)
        {
        }

        #endregion
        #region ShowViewModel

        protected void ShowViewModel(System.Type viewModelType, object parameterValues, bool addToHistory)
        {
            ShowViewModel(viewModelType, parameterValues, PresentationManager.GetPresentationBundle(null, addToHistory));
        }
        protected void ShowViewModel(System.Type viewModelType, IMvxBundle parameterBundle, bool addToHistory)
        {
            ShowViewModel(viewModelType, parameterBundle, PresentationManager.GetPresentationBundle(null, addToHistory));
        }
        protected void ShowViewModel(System.Type viewModelType, IDictionary<string, string> parameterValues, bool addToHistory)
        {
            ShowViewModel(viewModelType, parameterValues, PresentationManager.GetPresentationBundle(null, addToHistory));
        }
        protected void ShowViewModel(System.Type viewModelType, object parameterValues, bool addToHistory, string childRegionName)
        {
            ShowViewModel(viewModelType, parameterValues, PresentationManager.GetPresentationBundle(childRegionName, addToHistory));
        }
        protected void ShowViewModel(System.Type viewModelType, IMvxBundle parameterBundle, bool addToHistory, string childRegionName)
        {
            ShowViewModel(viewModelType, parameterBundle, PresentationManager.GetPresentationBundle(childRegionName, addToHistory));
        }
        protected void ShowViewModel(System.Type viewModelType, IDictionary<string, string> parameterValues, bool addToHistory, string childRegionName)
        {
            ShowViewModel(viewModelType, parameterValues, PresentationManager.GetPresentationBundle(childRegionName, addToHistory));
        }

        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1004:GenericMethodsShouldProvideTypeParameter")]
        protected void ShowViewModel<TViewModel>(object parameterValues, bool addToHistory) where TViewModel : IMvxViewModel
        {
            ShowViewModel<TViewModel>(parameterValues, PresentationManager.GetPresentationBundle(null, addToHistory));
        }
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1004:GenericMethodsShouldProvideTypeParameter")]
        protected void ShowViewModel<TViewModel>(IMvxBundle parameterBundle, bool addToHistory) where TViewModel : IMvxViewModel
        {
            ShowViewModel<TViewModel>(parameterBundle, PresentationManager.GetPresentationBundle(null, addToHistory));
        }
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1004:GenericMethodsShouldProvideTypeParameter")]
        protected void ShowViewModel<TViewModel>(IDictionary<string, string> parameterValues, bool addToHistory) where TViewModel : IMvxViewModel
        {
            ShowViewModel<TViewModel>(parameterValues, PresentationManager.GetPresentationBundle(null, addToHistory));
        }
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1004:GenericMethodsShouldProvideTypeParameter")]
        protected void ShowViewModel<TViewModel>(object parameterValues, bool addToHistory, string childRegionName) where TViewModel : IMvxViewModel
        {
            ShowViewModel<TViewModel>(parameterValues, PresentationManager.GetPresentationBundle(childRegionName, addToHistory));
        }
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1004:GenericMethodsShouldProvideTypeParameter")]
        protected void ShowViewModel<TViewModel>(IMvxBundle parameterBundle, bool addToHistory, string childRegionName) where TViewModel : IMvxViewModel
        {
            ShowViewModel<TViewModel>(parameterBundle, PresentationManager.GetPresentationBundle(childRegionName, addToHistory));
        }
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1004:GenericMethodsShouldProvideTypeParameter")]
        protected void ShowViewModel<TViewModel>(IDictionary<string, string> parameterValues, bool addToHistory, string childRegionName) where TViewModel : IMvxViewModel
        {
            ShowViewModel<TViewModel>(parameterValues, PresentationManager.GetPresentationBundle(childRegionName, addToHistory));
        }

        #endregion
        #region UnloadViewModel

        protected virtual void UnloadViewModel()
        {
            System.IDisposable viewModelResource;
            int iMax;

            iMax = this.ViewModelResources.Count;
            for (int i = iMax - 1; i >= 0; i--)
            {
                viewModelResource = this.ViewModelResources[i];
                if (viewModelResource != null)
                    viewModelResource.Dispose();
            }
            this.ViewModelResources.Clear();
        }

        #endregion
        #region Dispose

        private bool disposed = false;
        public void Dispose()
        {
            Dispose(true);
            System.GC.SuppressFinalize(this);
        }
        protected virtual void Dispose(bool disposing)
        {
            if (!disposed)
            {
                if (disposing)
                    UnloadViewModel();
                disposed = true;
            }
        }

        #endregion

        // Events
        #region Publish

        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic")]
        protected void Publish<TMessage>(TMessage message) where TMessage : MvxMessage
        {
            EventManager.Publish(message);
        }

        #endregion
        #region Subscribe

        protected void Subscribe<TMessage>(System.Action<TMessage> deliveryAction) where TMessage : MvxMessage
        {
            this.ViewModelResources.Add(EventManager.Subscribe(deliveryAction));
        }
        protected void Subscribe<TMessage1, TMessage2>(System.Action<TMessage1> deliveryAction1, System.Action<TMessage2> deliveryAction2)
            where TMessage1 : MvxMessage
            where TMessage2 : MvxMessage
        {
            this.ViewModelResources.AddRange(EventManager.Subscribe(deliveryAction1, deliveryAction2));
        }
        protected void Subscribe<TMessage1, TMessage2, TMessage3>(System.Action<TMessage1> deliveryAction1, System.Action<TMessage2> deliveryAction2,
            System.Action<TMessage3> deliveryAction3)
            where TMessage1 : MvxMessage
            where TMessage2 : MvxMessage
            where TMessage3 : MvxMessage
        {
            this.ViewModelResources.AddRange(EventManager.Subscribe(deliveryAction1, deliveryAction2, deliveryAction3));
        }
        protected void Subscribe<TMessage1, TMessage2, TMessage3, TMessage4>(System.Action<TMessage1> deliveryAction1, System.Action<TMessage2> deliveryAction2,
            System.Action<TMessage3> deliveryAction3, System.Action<TMessage4> deliveryAction4)
            where TMessage1 : MvxMessage
            where TMessage2 : MvxMessage
            where TMessage3 : MvxMessage
            where TMessage4 : MvxMessage
        {
            this.ViewModelResources.AddRange(EventManager.Subscribe(deliveryAction1, deliveryAction2, deliveryAction3, deliveryAction4));
        }

        #endregion

        #endregion
        #region Private Members

        #region LogManager

        private Sidvall.Logging.LogManager LogManager
        {
            get
            {
                return Sidvall.SystemContext.Current.LogManager;
            }
        }

        #endregion

        #region LogAsync

        private async Task LogAsync(System.Exception exception)
        {
            if (this.LogManager != null)
                await this.LogManager.WriteAsync(exception, Sidvall.Logging.LogCategories.Application);
        }

        #endregion
        #region OnCultureChangedInternal

        private async void OnCultureChangedInternal(CultureMessage item)
        {
            try
            {
                OnCultureChanged(item);
            }
            catch (System.Exception ex)
            {
                await LogAsync(ex);
                await Sidvall.UI.SystemContext.Current.DialogManager.ShowDialogErrorMessageAsync(ex);
            }
        }

        #endregion

        #endregion
        #region Constructors

        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes")]
        protected NavigatingObjectBase()
        {
            try
            {
                Subscribe<CultureMessage>(OnCultureChangedInternal);
            }
            catch
            {
            }
        }

        #endregion
    }
}
